using System;
using System.Collections.Generic;
using System.Text;
using System.Data;

namespace SubSonic
{
    public class Aggregate
    {
        #region Aggregates Factories

        public static Aggregate Count(TableSchema.TableColumn col)
        {
            Aggregate agg = new Aggregate(col, AggregateFunction.Count);
            return agg;
        }

        public static Aggregate Count(TableSchema.TableColumn col, string alias)
        {
            Aggregate agg = new Aggregate(col, alias, AggregateFunction.Count);
            return agg;
        }

        public static Aggregate Count(string columnName)
        {
            Aggregate agg = new Aggregate(columnName, AggregateFunction.Count);
            return agg;
        }

        public static Aggregate Count(string columnName, string alias)
        {
            Aggregate agg = new Aggregate(columnName, alias, AggregateFunction.Count);
            return agg;
        }

        public static Aggregate Sum(TableSchema.TableColumn col)
        {
            Aggregate agg = new Aggregate(col, AggregateFunction.Sum);
            return agg;
        }

        public static Aggregate Sum(string columnName)
        {
            Aggregate agg = new Aggregate(columnName, AggregateFunction.Sum);
            return agg;
        }

        public static Aggregate Sum(TableSchema.TableColumn col, string alias)
        {
            Aggregate agg = new Aggregate(col, alias, AggregateFunction.Sum);
            return agg;
        }

        public static Aggregate Sum(string columnName, string alias)
        {
            Aggregate agg = new Aggregate(columnName, alias, AggregateFunction.Sum);
            return agg;
        }

        public static Aggregate GroupBy(TableSchema.TableColumn col)
        {
            Aggregate agg = new Aggregate(col, AggregateFunction.GroupBy);
            return agg;
        }

        public static Aggregate GroupBy(string columnName)
        {
            Aggregate agg = new Aggregate(columnName, AggregateFunction.GroupBy);
            return agg;
        }

        public static Aggregate GroupBy(TableSchema.TableColumn col, string alias)
        {
            Aggregate agg = new Aggregate(col, alias, AggregateFunction.GroupBy);
            return agg;
        }

        public static Aggregate GroupBy(string columnName, string alias)
        {
            Aggregate agg = new Aggregate(columnName, alias, AggregateFunction.GroupBy);
            return agg;
        }

        public static Aggregate Avg(TableSchema.TableColumn col)
        {
            Aggregate agg = new Aggregate(col, AggregateFunction.Avg);
            return agg;
        }

        public static Aggregate Avg(string columnName)
        {
            Aggregate agg = new Aggregate(columnName, AggregateFunction.Avg);
            return agg;
        }

        public static Aggregate Avg(TableSchema.TableColumn col, string alias)
        {
            Aggregate agg = new Aggregate(col, alias, AggregateFunction.Avg);
            return agg;
        }

        public static Aggregate Avg(string columnName, string alias)
        {
            Aggregate agg = new Aggregate(columnName, alias, AggregateFunction.Avg);
            return agg;
        }

        public static Aggregate Max(TableSchema.TableColumn col)
        {
            Aggregate agg = new Aggregate(col, AggregateFunction.Max);
            return agg;
        }

        public static Aggregate Max(string columnName)
        {
            Aggregate agg = new Aggregate(columnName, AggregateFunction.Max);
            return agg;
        }

        public static Aggregate Max(TableSchema.TableColumn col, string alias)
        {
            Aggregate agg = new Aggregate(col, alias, AggregateFunction.Max);
            return agg;
        }

        public static Aggregate Max(string columnName, string alias)
        {
            Aggregate agg = new Aggregate(columnName, alias, AggregateFunction.Max);
            return agg;
        }

        public static Aggregate Min(TableSchema.TableColumn col)
        {
            Aggregate agg = new Aggregate(col, AggregateFunction.Min);
            return agg;
        }

        public static Aggregate Min(string columnName)
        {
            Aggregate agg = new Aggregate(columnName, AggregateFunction.Min);
            return agg;
        }

        public static Aggregate Min(TableSchema.TableColumn col, string alias)
        {
            Aggregate agg = new Aggregate(col, alias, AggregateFunction.Min);
            return agg;
        }

        public static Aggregate Min(string columnName, string alias)
        {
            Aggregate agg = new Aggregate(columnName, alias, AggregateFunction.Min);
            return agg;
        }

        public static Aggregate Variance(TableSchema.TableColumn col)
        {
            Aggregate agg = new Aggregate(col, AggregateFunction.Var);
            return agg;
        }

        public static Aggregate Variance(string columnName)
        {
            Aggregate agg = new Aggregate(columnName, AggregateFunction.Var);
            return agg;
        }

        public static Aggregate Variance(TableSchema.TableColumn col, string alias)
        {
            Aggregate agg = new Aggregate(col, alias, AggregateFunction.Var);
            return agg;
        }

        public static Aggregate Variance(string columnName, string alias)
        {
            Aggregate agg = new Aggregate(columnName, alias, AggregateFunction.Var);
            return agg;
        }

        public static Aggregate StandardDeviation(TableSchema.TableColumn col)
        {
            Aggregate agg = new Aggregate(col, AggregateFunction.StdDev);
            return agg;
        }

        public static Aggregate StandardDeviation(string columnName)
        {
            Aggregate agg = new Aggregate(columnName, AggregateFunction.StdDev);
            return agg;
        }

        public static Aggregate StandardDeviation(TableSchema.TableColumn col, string alias)
        {
            Aggregate agg = new Aggregate(col, alias, AggregateFunction.StdDev);
            return agg;
        }

        public static Aggregate StandardDeviation(string columnName, string alias)
        {
            Aggregate agg = new Aggregate(columnName, alias, AggregateFunction.StdDev);
            return agg;
        }

        #endregion


        #region .ctors

        private Aggregate() {}

        public static string GetFunctionType(Aggregate agg)
        {
            return Enum.GetName(typeof(AggregateFunction), agg.AggregateType);
        }

        public Aggregate(string columnName, AggregateFunction aggregateType)
        {
            _columnName = columnName;
            _aggregateType = aggregateType;
            _alias = GetFunctionType(this) + "Of" + columnName;
        }

        public Aggregate(string columnName, string alias, AggregateFunction aggregateType)
        {
            _columnName = columnName;
            _aggregateType = aggregateType;
            _alias = alias;
        }

        public Aggregate(TableSchema.TableColumn column, AggregateFunction aggregateType)
        {
            _columnName = column.QualifiedName;
            _aggregateType = aggregateType;
            _alias = GetFunctionType(this) + "Of" + column.ColumnName;
        }

        public Aggregate(TableSchema.TableColumn column, string alias, AggregateFunction aggregateType)
        {
            _columnName = column.QualifiedName;
            _alias = alias;
            _aggregateType = aggregateType;
        }

        private AggregateFunction _aggregateType = AggregateFunction.Count;

        #endregion


        public AggregateFunction AggregateType
        {
            get { return _aggregateType; }
            set { _aggregateType = value; }
        }

        private string _columnName;

        public string ColumnName
        {
            get { return _columnName; }
            set { _columnName = value; }
        }

        private string _alias;

        public string Alias
        {
            get { return _alias; }
            set { _alias = value; }
        }

        public override string ToString()
        {
            string result;

            if(AggregateType == AggregateFunction.GroupBy)
                result = ColumnName;
            else
            {
                string colPrefix = "";
                string functionName = GetFunctionType(this);
                functionName = Sugar.Strings.CamelToProper(functionName).ToUpper();
                string aggFormat = " {0}({1}) as '{2}'";
                result = string.Format(aggFormat, functionName, ColumnName, Alias);
            }

            return result;
        }
    }
}
